package com.qudian.pay.log.filter;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.AntPathMatcher;
import com.google.common.collect.Lists;
import com.qudian.pay.log.util.HttpHeaderUtils;

/**
 * @Description: 在进行过滤的时候，将优先进行后缀过滤，然后再说pattern过滤
 * @ClassName: AbstractFilter
 * @author gaoxiang
 * @date 2015年11月24日 下午10:46:41
 */
public abstract class AbstractFilter implements Filter {
	
	/**
	 * Filter进行过滤时，那些资源将会被忽略的配置，以Pattern形式提供，用在Filter类中
	 */
	public static final String URL_IGNORE_LIST_PATTERN = "ignoreListPattern";
	
	/**
	 * @Fields URL_IGNORE_LIST_SUFFIX : Filter进行过滤时，那些资源将会被忽略的配置，以后缀形式提供，用在Filter类中
	 */
	public static final String URL_IGNORE_LIST_SUFFIX = "ignoreListSuffix";
	
	/**
	 * @Fields ignoreList : 将要忽略的资源的列表
	 */
	private String ignoreList = "gif,css,ico,js,swf,jpg,jpeg,png,tiff,pcx";
	
	private List<String> ignorePattern = Lists.newArrayList();
	
	private FilterConfig filterConfig;
	
	@Override
	public void destroy() {
	}
	
	@Override
	public final void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
		String temp = filterConfig.getInitParameter(URL_IGNORE_LIST_PATTERN);
		if (StringUtils.isNotBlank(temp)) {
			String[] tempIgnorePattern = StringUtils.split(temp, ",");
			for (String tip : tempIgnorePattern) {
				ignorePattern.add(tip);
			}
		}
		temp = filterConfig.getInitParameter(URL_IGNORE_LIST_SUFFIX);
		if (StringUtils.isNotBlank(temp)) {
			if (!temp.startsWith(",")) {
				ignoreList += ",";
			}
			ignoreList += temp;
		}
		doInit(filterConfig);
	}
	
	protected void doInit(FilterConfig filterConfig) throws ServletException {
	}
	
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		if (checkIgnoreFilter((HttpServletRequest) request)) {
			chain.doFilter(request, response);
		} else {
			doFilterLogic(request, response, chain);
		}
	}
	
	/**
	 * @Description: 实际的过滤逻辑
	 * @return void 返回类型
	 * @author gaoxiang
	 * @date 2016年5月17日 下午6:03:22
	 */
	protected abstract void doFilterLogic(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
	
	/**
	 * @Description: 检查是否忽略当前请求
	 * @param request
	 * @return boolean 返回类型
	 * @author gaoxiang
	 * @date 2016年5月17日 下午5:56:07
	 */
	protected boolean checkIgnoreFilter(HttpServletRequest request) {
		String uri = HttpHeaderUtils.getRequestURL(request);
		int p = uri.lastIndexOf(".");
		// 1. 按照后缀进行检查，可以处理大部分内容
		if (p > -1) {
			try {
				String type = uri.substring(p + 1);
				if (ignoreList.indexOf(type) > -1 && !uri.contains("Captcha")) {
					return true;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// 2. 按照Pattern进行检查
		for (String pattern : ignorePattern) {
			if (stringMatch(uri, pattern)) {
				return true;
			}
		}
		return false;
	}
	
	// 获取在web.xml中配置的参数
	protected String findInitParameter(String paramName, String defaultValue) {
		// 取filter参数
		String value = StringUtils.trimToNull(filterConfig.getInitParameter(paramName));
		// 如果未取到，则取全局参数
		if (value == null) {
			value = StringUtils.trimToNull(filterConfig.getServletContext().getInitParameter(paramName));
		}
		// 如果未取到，则取默认值
		if (value == null) {
			value = defaultValue;
		}
		return value;
	}
	
	public boolean stringMatch(String source, String pattern) {
		// 采用AntPath匹配方法
		if (new AntPathMatcher().match(pattern, source)) {
			return true;
		}
		// 正则表达式匹配
		Map<String, Pattern> patternCache = Collections.synchronizedMap(new HashMap<String, Pattern>());
		try {
			Pattern sp = null;
			if (patternCache.containsKey(pattern)) {
				sp = patternCache.get(pattern);
			} else {
				sp = Pattern.compile(pattern);
				patternCache.put(pattern, sp);
			}
			Matcher matcher = sp.matcher(source);
			if (matcher.find()) {
				return true;
			}
		} catch (Exception e) {
		}
		return false;
	}
}
